Intro: Analysis of libfuzzer && LLVM
libfuzzer build
编译流程
环境Ubuntu16.041
2
3
4
5git clone https://github.com/Dor1s/libfuzzer-workshop.git
sudo sh checkout_build_install_llvm.sh
sudo apt-get install -ymake autoconf automake libtool pkg-config zlib1g-dev
cd libfuzzer-workshop/libFuzzer
Fuzzer/build.sh
趁着编译的时候去详细了解一下libfuzzer其中的内存监控算法
The run-time library replaces the malloc and free functions. The memory around malloc-ed regions (red zones) is poisoned. The free-ed memory is placed in quarantine and also poisoned. ==Every memory access in the program is transformed by the compiler in the following way:==
Before: 变量赋值1
*address = ...; // or: ... = *address;
After:加上检测1
2
3
4if (IsPoisoned(address)) {
ReportError(address, kAccessSize, kIsWrite);
}
*address = ...; // or: ... = *address;
Memory mapping and Instrumentation
- shadwos 和 main memory
- 编译器进行了如下插桩
1
2
3
4shadow_address = MemToShadow(address);
if (ShadowIsPoisoned(shadow_address)) {
Repozhuang'tai'yrtError(address, kAccessSize, kIsWrite);
}
并且针对shadows的one byte进行了与main memory的状态映射1
2
3
4
5
6
7
8
9
10
11
12
13
14byte *shadow_address = MemToShadow(address);
byte shadow_value = *shadow_address;
if (shadow_value) {
if (SlowPathCheck(shadow_value, address, kAccessSize)) {
ReportError(address, kAccessSize, kIsWrite);
}
}
// Check the cases where we access first k bytes of the qword
// and these k bytes are unpoisoned.
bool SlowPathCheck(shadow_value, address, kAccessSize) {
last_accessed_byte = (address & 7) + kAccessSize - 1;
return (last_accessed_byte >= shadow_value);
}
针对全内存,判断poison==0 :fastpath
针对非全内存,SlowPathCheck,(last_accessed_byte:最后写入的数据大小;shadow_value:能写入的数据大小)
针对部分fastpath不能满足的非对齐oob访问,我的想法是干脆放弃fastpath转用slowpath,结果看了issue发现确实是这样,但是有一定的性能损耗,得不偿失。
研究这部分算法也是得不偿失然鹅。。
对于栈做了如下插桩:1
2
3
4
5
6
7
8
9
10
11
12
13void foo() {
char redzone1[32]; // 32-byte aligned
char a[8]; // 32-byte aligned
char redzone2[24];
char redzone3[32]; // 32-byte aligned
int *shadow_base = MemToShadow(redzone1);
shadow_base[0] = 0xffffffff; // poison redzone1
shadow_base[1] = 0xffffff00; // poison redzone2, unpoison 'a'
shadow_base[2] = 0xffffffff; // poison redzone3
...
shadow_base[0] = shadow_base[1] = shadow_base[2] = 0; // unpoison all
return;
}
addresssanitize 源码分析:
1 | bool AddressSanitizerModule::runOnModule(Module &M) { |
sum
- 内存监控围绕 RZ 插桩来实现
- 对一些内存的状态进行shadow的映射,访问的时候进行状态检测
libfuzzer貌似编译完了,我去看看
radamsa
【+】radamsa
学习libfuzzer中遇到的种种:
- 有corpus
- LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)的data是随机的,但size需要自己设置 max_len.
- libfuzzer option 指北
- 编译时用到的参数可以在 clang -help 中查看
- -fsanitize=address: 表示使用 AddressSanitizer
- -fsanitize-coverage=trace-pc-guard: 为 libfuzzer 提供代码覆盖率信息
- Seed: 1608565063 说明这次的种子数据
- -max_len is not provided, using 64 , -max_len 用于设置最大的数据长度,默认为 64
- ASAN_OPTIONS=symbolize=1 ./first_fuzzer ./crash-id 显示栈
- 简单来说,如果我们要 fuzz 一个程序,找到一个入口函数,然后利用LLVMFuzzerTestOneInput就可以完成基本功能,然鹅:
- 我发现libfuzzer-interface还有几个接口类似于LLVMFuzzerCustomMutator。
练习写第一个fuzzer
代码:
测试最基本的溢出
编译选项:
【+】 -fsanitize=fuzzer: 代码覆盖率
【+】 -fsanitize=address:启用 AddressSanitizer
【+】 -g:详细调试信息
运行选项:
【+】 -seed:制定随机数
【+】 -max_len:指定 Data 最大长度
【+】 +dir: 指定 corpus
第二个
1 | constexpr auto kMagicHeader = "ZN_2016"; |
fuzzer_code:1
2
3
4
5
6
7#include "vulnerable_functions.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
VulnerableFunction2(data, size, true);
VulnerableFunction2(data, size, false);
return 0;
}
这里有个tip:bool类型的变量太好遍历了,为了覆盖率测试两次就好:)
但是会如何影响覆盖率呢?是不是覆盖的呢?
试一试把原函数中return true去掉,fuzzer.cc换成:1
2
3
4
5
6#include "vulnerable_functions.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
VulnerableFunction2(data, size, false);
return 0;
}
覆盖率25,上一个覆盖率也是25(均crash)
再去掉1
if (!verify_hash)
覆盖率降为24
wow很清晰:覆盖率就是整个fuzzer一趟测试触及的 basic-block 总个数。
第三个
加了一个& :1
2
3
4
5
6constexpr std::size_t kZn2016VerifyHashFlag = 0x0001000;
bool VulnerableFunction3(const uint8_t* data, size_t size, std::size_t flags) {
bool verify_hash = flags & kZn2016VerifyHashFlag;
return VulnerableFunction2(data, size, verify_hash);
}
那么还是遍历一下:1
2
3
4
5
6extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
VulnerableFunction3(data, size, 0x00);
VulnerableFunction3(data, size, 0x1001);
return 0;
}
crash:)
第四个
写到这里想到,写fuzz的目的就是crashcrashcrash,所以尽可能调整fuzz代码达到crash即可,没必要局限于格式。
开始第四个CVE-2014-0160:
build
1 | tar xzf openssl1.0.1f.tgz |
fuzzer.cc:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33// Copyright 2016 Google Inc. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#ifndef CERT_PATH
# define CERT_PATH
#endif
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
SSL_CTX *sctx;
assert (sctx = SSL_CTX_new(TLSv1_method()));
assert(SSL_CTX_use_certificate_file(sctx, CERT_PATH "server.pem",
SSL_FILETYPE_PEM));
assert(SSL_CTX_use_PrivateKey_file(sctx, CERT_PATH "server.key",
SSL_FILETYPE_PEM));
SSL *server = SSL_new(sctx);
BIO *sinbio = BIO_new(BIO_s_mem());
BIO *soutbio = BIO_new(BIO_s_mem());
SSL_set_bio(server, sinbio, soutbio);
SSL_set_accept_state(server);
BIO_write(sinbio, Data, Size);
SSL_do_handshake(server);
SSL_free(server);
return 0;
}
编译选项:1
clang++ -g openssl_fuzzer.cc -O2 -fno-omit-frame-pointer -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp,trace-gep,trace-div -I openssl1.0.1f/include openssl1.0.1f/libssl.a openssl1.0.1f/libcrypto.a ../../libFuzzer/libFuzzer.a -o openssl_fuzzer
跑出来了好几次 oom 和 leakmem ?
- 去掉 leak
- 扩大内存
1
./openssl_fuzzer -detect_leaks=0 -rss_limit_mb=4096
花了一分钟才跑出来crash,why???
如果把初始化api分开来看呢?1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42// Copyright 2016 Google Inc. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#ifndef CERT_PATH
# define CERT_PATH
#endif
SSL_CTX *Init() {
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
SSL_CTX *sctx;
assert (sctx = SSL_CTX_new(TLSv1_method()));
/* These two file were created with this command:
openssl req -x509 -newkey rsa:512 -keyout server.key \
-out server.pem -days 9999 -nodes -subj /CN=a/
*/
assert(SSL_CTX_use_certificate_file(sctx, CERT_PATH "server.pem",
SSL_FILETYPE_PEM));
assert(SSL_CTX_use_PrivateKey_file(sctx, CERT_PATH "server.key",
SSL_FILETYPE_PEM));
return sctx;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static SSL_CTX *sctx = Init();
SSL *server = SSL_new(sctx);
BIO *sinbio = BIO_new(BIO_s_mem());
BIO *soutbio = BIO_new(BIO_s_mem());
SSL_set_bio(server, sinbio, soutbio);
SSL_set_accept_state(server);
BIO_write(sinbio, Data, Size);
SSL_do_handshake(server);
SSL_free(server);
return 0;
}
五秒钟???
到底是那点会影响 fuzz 效率呢。。。
llvm PASS
这一段当成是插入的知识,再看 ASAN 源码过程中意识到编写llvm pass 一定会对以后独自编写 fuzzer 框架有用的,因此今天除了接着研究ASAN源码之余要学习一下llvm pass的编写,目标是熟练掌握 ModulePass 以及 FunctionPass。
资料
http://www.voidcn.com/article/p-mgwevrjr-brn.html
http://llvm.org/docs/WritingAnLLVMPass.html#the-modulepass-class
https://zhuanlan.zhihu.com/p/26129264
https://blog.csdn.net/Mr_Megamind/article/details/78896717
环境配置
1 | apt-get install git |
使用clang
hello.c1
2
3
4
5
6#include <stdio.h>
int main() {
printf("hello worldn");
return 0;
}
complier it1
clang hello.c -o hello
输出llvmbitcode1
clang -O3 -emit-llvm hello.c -c -o hello.bc
-emit-llvm选项可与-S或-c选项一起使用,以分别为代码生成LLVM .ll或.bc文件。两者都是LLVM Bitcode,区别在于前者是可读的文本,后者是不可读的二进制格式。
使用lli执行.bc1
lli hello.bc
使用llvm-dis对.bc反汇编1
llvm-dis < hello.bc
使用llc将.bc生成.s1
llc hello.bc -o hello.s
常用的编译选项:
- -c: 只激活预处理,编译,和汇编,也就是他只把程序做成obj文件
- -S: 只激活预处理和编译,就是指把文件编译成为汇编代码。
- -O+num:优化等级
- -emit-llvm:llvmbitcode 可与-c或-S 一同使用,但不能有链接
llvm IR
https://releases.llvm.org/2.6/docs/tutorial/JITTutorial1.html
https://releases.llvm.org/2.6/docs/LangRef.html
这块先挖个坑,过年后填回来。
我来填坑了:
Identifiers
- 全局变量:@
- 局部有命名的变量:%+string
- 局部未命名的变量:%+num
- 注释:;
- 如果计算结果未分配给命名值,则会创建未命名的临时值。
- 未命名的临时数据按顺序编号
High Level Structure
- Module 是llvm的翻译单元
- 每个Module包含functions,全局变量以及符号表
- module可以被llvm-linker操作
- function和全局变量都可以被看作global value
指令
ret:
1
ret <type> <value>
1
2
3ret i32 5
ret void
ret { i32, i8 } { i32 4, i8 2 } ; Return a struct of values 4 and 2br:
1
br i1 <cond>, label <iftrue>, label <iffalse>
1
2
3
4
5
6
7Test:
%cond = icmp eq i32 %a, %b
br i1 %cond, label %IfEqual, label %IfUnequal
IfEqual:
ret i32 1
IfUnequal:
ret i32 0switch:
1
switch <intty> <value>, label <defaultdest> [ <intty> <val>, label <dest> ... ]
1
2
3
4
5
6
7
8
9
10
11; Emulate a conditional br instruction
%Val = zext i1 %value to i32
switch i32 %Val, label %truedest [ i32 0, label %falsedest ]
; Emulate an unconditional br instruction
switch i32 0, label %dest [ ]
; Implement a jump table:
switch i32 %val, label %otherwise [ i32 0, label %onzero
i32 1, label %onone
i32 2, label %ontwo ]invoke:
1
2<result> = invoke [cconv] [ret attrs] <ptr to function ty> <function ptr val>(<function args>) [fn attrs]
to label <normal label> unwind label <exception label>1
2
3
4%retval = invoke i32 @Test(i32 15) to label %Continue
unwind label %TestCleanup ; {i32}:retval set
%retval = invoke coldcc i32 %Testfnptr(i32 15) to label %Continue
unwind label %TestCleanup ; {i32}:retval set
熟悉 LLVM API 使用
code1:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48using namespace llvm;
Module* makeLLVMModule() {
// Module Construction
Module* mod = new Module("test", getGlobalContext());
Constant* c = mod->getOrInsertFunction("mul_add",
/*ret type*/ IntegerType::get(32),
/*args*/ IntegerType::get(32),
IntegerType::get(32),
IntegerType::get(32),
/*varargs terminated with null*/ NULL);
Function* mul_add = cast<Function>(c);
mul_add->setCallingConv(CallingConv::C);
Function::arg_iterator args = mul_add->arg_begin();
Value* x = args++;
x->setName("x");
Value* y = args++;
y->setName("y");
Value* z = args++;
z->setName("z");
BasicBlock* block = BasicBlock::Create(getGlobalContext(), "entry", mul_add);
IRBuilder<> builder(block);
Value* tmp = builder.CreateBinOp(Instruction::Mul,
x, y, "tmp");
Value* tmp2 = builder.CreateBinOp(Instruction::Add,
tmp, z, "tmp2");
builder.CreateRet(tmp2);
return mod;
}
int main(int argc, char**argv) {
Module* Mod = makeLLVMModule();
verifyModule(*Mod, PrintMessageAction);
PassManager PM;
PM.add(createPrintModulePass(&outs()));
PM.run(*Mod);
delete Mod;
return 0;
}
code2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76Module* makeLLVMModule() {
// constract module
Module* mod = new Module("test", getGlobalContext());
// constract func
Constant* c = mod->getOrInsertFunction("mul_add",
/*ret type*/ IntegerType::get(32),
/*args*/ IntegerType::get(32),
IntegerType::get(32),
/*varargs terminated with null*/ NULL);
// cast this function
Function* gcd = cast<Function>(c);
//set arg
Function::arg_iterator args = gcd->arg_begin();
Value* x = args++;
x->setName("x");
Value* y = args++;
y->setName("y");
//set basic blocks
BasicBlock* entry = BasicBlock::Create(getGlobalContext(), ("entry", gcd);
BasicBlock* ret = BasicBlock::Create(getGlobalContext(), ("return", gcd);
BasicBlock* cond_false = BasicBlock::Create(getGlobalContext(), ("cond_false", gcd);
BasicBlock* cond_true = BasicBlock::Create(getGlobalContext(), ("cond_true", gcd);
BasicBlock* cond_false_2 = BasicBlock::Create(getGlobalContext(), ("cond_false", gcd);
//use IRBuild to fill the <entry> basicblocks
IRBuilder<> builder(entry);
//fill
Value* xEqualsY = builder.CreateICmpEQ(x, y, "tmp");
builder.CreateCondBr(xEqualsY, ret, cond_false);
//use <SetInsertPoint> to retarget the targetBB
builder.SetInsertPoint(ret);
//fill
builder.CreateRet(x);
builder.SetInsertPoint(cond_true);
Value* yMinusX = builder.CreateSub(y, x, "tmp");
std::vector<Value*> args1;
args1.push_back(x);
args1.push_back(yMinusX);
Value* recur_1 = builder.CreateCall(gcd, args1.begin(), args1.end(), "tmp");
builder.CreateRet(recur_1);
builder.SetInsertPoint(cond_false_2);
Value* xMinusY = builder.CreateSub(x, y, "tmp");
std::vector<Value*> args2;
args2.push_back(xMinusY);
args2.push_back(y);
Value* recur_2 = builder.CreateCall(gcd, args2.begin(), args2.end(), "tmp");
builder.CreateRet(recur_2);
return mod;
}
}
int main(int argc, char**argv) {
Module* Mod = makeLLVMModule();
verifyModule(*Mod, PrintMessageAction);
PassManager PM;
PM.add(createPrintModulePass(&outs()));
PM.run(*Mod);
delete Mod;
return 0;
}
环境配置
1 | apt-get install git |
CMakeList
使用cmake1
2
3
4
5
6
7
8<project dir>/
|
CMakeLists.txt
<pass name>/
|
CMakeLists.txt
Pass.cpp
...
1
2
3
4
5
6find_package(LLVM REQUIRED CONFIG)
add_definitions(${LLVM_DEFINITIONS})
include_directories(${LLVM_INCLUDE_DIRS})
add_subdirectory(<pass name>)
cmake1:1
2
3
4
5
6
7
8
9
10
11
12if(NOT DEFINED ENV{LLVM_HOME})
message(FATAL_ERROR "$LLVM_HOME is not defined")
endif()
if(NOT DEFINED ENV{LLVM_DIR})
set(ENV{LLVM_DIR} $ENV{LLVM_HOME}/lib/cmake/llvm)
endif()
find_package(LLVM REQUIRED CONFIG)
add_definitions(${LLVM_DEFINITIONS})
include_directories(${LLVM_INCLUDE_DIRS})
link_directories(${LLVM_LIBRARY_DIRS})
add_subdirectory(P1umer) # Use your pass name here.
cmake2:1
2
3
4
5
6
7
8
9
10
11
12
13add_library(P1umerPass MODULE
# List your source files here.
P1umer.cpp
)
# Use C++11 to compile your pass (i.e., supply -std=c++11).
target_compile_features(P1umerPass PRIVATE cxx_range_for cxx_auto_type)
# LLVM is (typically) built with no C++ RTTI. We need to match that;
# otherwise, we'll get linker errors about missing RTTI data.
set_target_properties(P1umerPass PROPERTIES
COMPILE_FLAGS "-fno-rtti"
)
编写一个入门的pass示例
p1umer.cpp:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
using namespace llvm;
namespace {
struct P1umerPass : public FunctionPass {
static char ID;
P1umerPass() : FunctionPass(ID) {}
virtual bool doInitialization(Module &) override {
printf("11111111111\n");
return false;
}
virtual bool doFinalization(Module &) {
printf("22222222222\n");
return false;
}
virtual bool runOnFunction(Function &F) {
errs() << "I saw a function called " << F.getName() << "!\n";
return false;
}
};
}
char P1umerPass::ID = 0;
// Automatically enable the pass.
// http://adriansampson.net/blog/clangpass.html
static RegisterPass<P1umerPass> X("P1umer", "Hello P1umer");
use it:1
2clang -c -emit-llvm hello.c -o hello.bc
opt -load ./libP1umerPass.so -P1umer hello.bc
output:1
2
311111111111
I saw a function called mul_add!
22222222222
熟悉依照CFG构建代码
1 | using namespace llvm; |
code2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76Module* makeLLVMModule() {
// constract module
Module* mod = new Module("test", getGlobalContext());
// constract func
Constant* c = mod->getOrInsertFunction("mul_add",
/*ret type*/ IntegerType::get(32),
/*args*/ IntegerType::get(32),
IntegerType::get(32),
/*varargs terminated with null*/ NULL);
// cast this function
Function* gcd = cast<Function>(c);
//set arg
Function::arg_iterator args = gcd->arg_begin();
Value* x = args++;
x->setName("x");
Value* y = args++;
y->setName("y");
//set basic blocks
BasicBlock* entry = BasicBlock::Create(getGlobalContext(), ("entry", gcd);
BasicBlock* ret = BasicBlock::Create(getGlobalContext(), ("return", gcd);
BasicBlock* cond_false = BasicBlock::Create(getGlobalContext(), ("cond_false", gcd);
BasicBlock* cond_true = BasicBlock::Create(getGlobalContext(), ("cond_true", gcd);
BasicBlock* cond_false_2 = BasicBlock::Create(getGlobalContext(), ("cond_false", gcd);
//use IRBuild to fill the <entry> basicblocks
IRBuilder<> builder(entry);
//fill
Value* xEqualsY = builder.CreateICmpEQ(x, y, "tmp");
builder.CreateCondBr(xEqualsY, ret, cond_false);
//use <SetInsertPoint> to retarget the targetBB
builder.SetInsertPoint(ret);
//fill
builder.CreateRet(x);
builder.SetInsertPoint(cond_true);
Value* yMinusX = builder.CreateSub(y, x, "tmp");
std::vector<Value*> args1;
args1.push_back(x);
args1.push_back(yMinusX);
Value* recur_1 = builder.CreateCall(gcd, args1.begin(), args1.end(), "tmp");
builder.CreateRet(recur_1);
builder.SetInsertPoint(cond_false_2);
Value* xMinusY = builder.CreateSub(x, y, "tmp");
std::vector<Value*> args2;
args2.push_back(xMinusY);
args2.push_back(y);
Value* recur_2 = builder.CreateCall(gcd, args2.begin(), args2.end(), "tmp");
builder.CreateRet(recur_2);
return mod;
}
}
int main(int argc, char**argv) {
Module* Mod = makeLLVMModule();
verifyModule(*Mod, PrintMessageAction);
PassManager PM;
PM.add(createPrintModulePass(&outs()));
PM.run(*Mod);
delete Mod;
return 0;
}
编写一个稍复杂的pass
code1:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28using namespace llvm;
namespace {
struct IterInsideBB : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
IterInsideBB() : FunctionPass(ID) {}
bool runOnFunction(Function &F) override {
errs() << "Function name: ";
errs() << F.getName() << '\n';
for(Function::iterator bb = F.begin(), e = F.end(); bb!=e; bb++)
{
errs()<<"BasicBlock name = "<< bb->getName() <<"\n";
errs()<<"BasicBlock size = "<< bb->size() << "\n\n";
for(BasicBlock::iterator i = bb->begin(), i2 = bb->end(); i!=i2; i++)
{
outs()<<" "<< *i <<"\n";
}
}
return false;
}
};
}
char IterInsideBB::ID = 0;
static RegisterPass<IterInsideBB> X("IterInsideBB", "Iterate inside basicblocks inside a Function");
code2:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32namespace {
struct UseDef : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
UseDef() : FunctionPass(ID) {}
bool runOnFunction(Function &F) override {
errs() << "Function name: ";
errs() << F.getName() << '\n';
for(Function::iterator bb = F.begin(), e = F.end(); bb!=e; bb++)
{
for(BasicBlock::iterator i = bb->begin(), i2 = bb->end(); i!=i2; i++)
{
Instruction * inst = dyn_cast<Instruction>(i);
if(inst->getOpcode() == Instruction::Add)
{
for(Use &U: inst -> operands())
{
Value * v = U.get();
outs()<< *v <<"\n";
}
}
}
}
return false;
}
};
}
char UseDef::ID = 0;
static RegisterPass<UseDef> X("UseDef", "This is use-def Pass");
v1<-loadint 8
v2<-operation add v1, v2